With the increasing popularity of object-oriented programming languages and systems, the development of distributed object systems has presented new challenges regarding the creation and management in general of the objects within these distributed systems. In particular, functions that control the life cycle of objects such as creation, activation, destruction, etc., may be implemented according to particular semantics dictating a particular protocol, or method of implementation. However, rather than there being a single set of obvious semantics for all objects, there appears to be a wide range of possible object semantics, often reflecting different application requirements. For example, there are distributed object systems that include integrated support for features such as replication, atomic transactions, object migration, and persistence. But there are also distributed object systems that provide only minimal features and instead concentrate on high performance.
One possible reaction to this diversity is to attempt to invent a single distributed object system for objects that includes all possible features. Unfortunately, the list of possible features is continually expanding, and not all features are necessarily compatible. For example, a high performance system may not want its objects to include support for the features of persistence or atomicity. Moreover, there are often a variety of different ways of implementing a given set of semantics. Having a single system prevents applications from exploiting new and improved features that may better reflect their real needs. For example, in order to increase reliability, it may be desired to support the feature of object replication. However, it would not be desirable to have client application code doing extra work simply to talk to replicated objects, so it would be preferable to support replication "underneath the covers", as part of the object's invocation mechanism. But there are many different ways of implementing replication, and it is undesirable to build in support for some particular set of features while implicitly rejecting others.
There are a wide variety of features or object mechanisms that a distributed object system might provide. By way of example, a distributed object system may provide such features such as replication, atomic transactions, object migration, persistence, naming, event notification, relationships, server activation, clean shutdowns, transactions, security, and enablement of filters (compression, encryption, tracing, debugging, etc.). These features may also be called services and may be provided by an Object Services module as part of a distributed object system. Past distributed object systems have suffered in that they were unable to provide a flexible subset of these features for different applications, much less for different objects within an application. Past systems only provided a fixed set of these features.
This deficiency may be addressed through the notion of a subcontract. Subcontracts and their use are described in above-referenced patent application Ser. No. 08/554,794. The notion of a subcontract is also described in "Subcontract: A Flexible Base for Distributed Programming" by G. Hamilton, M. Powell and J. Mitchell, published by Sun Microsystems Laboratories, Inc., 1993. Subcontracts and their associated functionality may be implemented in many different ways. By way of example, one such implementation is herein described.
Through the use of subcontracts, an application may specify which of the various above features (among others) it wishes to take advantage of, or may even specify different groups of features that may be used by different objects within the application. A group or a permutation of these features is implemented by a subcontract. Thus, each object within an application may utilize a particular subcontract. A group of desired features may be represented by a quality of service list that specifies these features. A subcontract, then, provides functionality consistent with a particular quality of service within a distributed object application and may provide other functionalities associated with that subcontract. An object may have one subcontract associated with it at a given time. Subcontracts are separate from object interfaces and object implementations. Thus, it is easy for object implementers to either select and use an existing subcontract, or to implement a new subcontract. Correspondingly, application level programmers need not be aware of the specific subcontracts that are being used for particular objects. A subcontract associated with an object allows the business of implementing an object to be separate from the business of implementing the object mechanisms or features provided by the system. Subcontracts also enable certain of the object invocation functions to be decoupled from a transport layer of a system, thus allowing the transport layer to function with different systems.
The availability of subcontracts enable object implementers to choose from a range of different object mechanisms (or features) without requiring that every object implementer must become familiar with the details of the object implementation machinery. The set of features that subcontracts provide are the right levers for obtaining control within a distributed environment. By design, all of the key actions taken on remote objects will involve the object's subcontract in one way or another. By way of example, actions such as object creation, object reference creation, object deactivation and revocation, and determining the references to an object all involve the object's subcontract. Subcontracts provide an effective way for plugging in different policies for different objects and are successful in reducing the functionality that must be provided by the base system.
However, one drawback with some distributed object systems is that servant objects themselves have been unable to call these actions directly. For example, servants were unable to call the functions "deactivate", "revoke", "expect no remaining references" or "get object reference" upon themselves. This deficiency reduced the flexibility of these systems. And another important drawback of certain distributed object systems is that the mechanism by which a particular subcontract was associated with a particular object has not been flexible enough. That is, these mechanisms have been able to associate a particular subcontract with an object definition or an object class, but have not been able to associate a subcontract with an instance of a class, or the object itself. This deficiency may be better explained by reference to FIG. 2.
FIG. 2 illustrates an example of how one particular distributed object application might be implemented. In this application the developer has defined an object type by way of an interface definition 122. This interface definition may be implemented by way of an Interface Definition Language (IDL) as will be appreciated by those skilled in the art. An interface specifies the operations and attributes available for an object type. For example, the interface COUNTER 122 specifies an object type that includes one operation "increment" and one attribute "maximum". If the developer wishes to create objects (also called instances or servants) of this object type that utilize the services of a particular subcontract X, he or she must specify this subcontract X in the class definition for that object type. As shown here, the developer has specified subcontract X for servant class A 124. Thus, the two servants created at run time, servant A1 128 and servant A2 130, will have the functionality associated with subcontract X by virtue of their being instantiated from servant class A. The drawback is that this subcontract X must be specified during application development before compile time of the servant class A.
For example, if the developer also wishes to create servants of the same object type that implement a different subcontract Y, the developer must create a whole new servant class because only one subcontract may be specified for a given servant class. As shown here, the developer has created a separate servant class B 126 which also implements the interface COUNTER. Servant class B is identical to servant class A except that servant class B specifies subcontract Y instead of subcontract X. In this fashion, a servant B1 132 may now be instantiated at run time with the functionality associated with subcontract Y. The problem is that if a developer wishes multiple servants of a given interface to utilize different subcontracts, he or she must write or specify a different servant class for each subcontract desired. This excess coding is time consuming and wasteful. Furthermore, the system is less flexible because subcontracts may only be associated with servants at compile time and not at run time. And some systems are even less flexible. Some systems require that a subcontract be specified in the object's interface, thus requiring needless duplication in order to have one interface for each type of subcontract desired for servant objects.
Accordingly, it would be desirable to have a mechanism for dynamically associating a subcontract with an individual servant (an object instance) at run time instead of with a servant class or interface at compile time. Such a mechanism would also be compatible with various of the object life cycle functions.